#pragma once
#include <map>
#include <mutex>
#include <thread>
//template<class Type>
//class CListWithLock
//{
//public:
//	POSITION AddTail(Type element)
//	{
//		m_oLock.Lock();
//		POSITION pos = m_oList.AddTail(element);
//		m_oLock.Unlock();
//		return pos;
//	}
//
//	Type GetHead()
//	{
//		Type result;
//		memset(&result, 0, sizeof(result));
//		m_oLock.Lock();
//		if (0 < m_oList.GetSize())
//		{
//			result = m_oList.GetHead();
//		}
//		m_oLock.Unlock();
//		return result;
//	}
//
//	Type RemoveHead()
//	{
//		Type result;
//		memset(&result, 0, sizeof(result));
//		m_oLock.Lock();
//		if (0 < m_oList.GetSize())
//			result = m_oList.RemoveHead();
//		m_oLock.Unlock();
//		return result;
//	}
//
//	void RemoveAt(POSITION &pos)
//	{
//		if (pos)
//		{
//			m_oLock.Lock();
//			m_oList.RemoveAt(pos);
//			pos = nullptr;
//			m_oLock.Unlock();
//		}
//	}
//
//	void RemoveAll()
//	{
//		m_oLock.Lock();
//		m_oList.RemoveAll();
//		m_oLock.Unlock();
//	}
//
//	int  GetCount()
//	{
//		m_oLock.Lock();
//		int nCount = m_oList.GetCount();
//		m_oLock.Unlock();
//		return nCount;
//	}
//
//	CListWithLock<Type> & operator=(CListWithLock<Type>& objectSrc)
//	{
//		m_oLock.Lock();
//		m_oList.RemoveAll();
//		auto pos = objectSrc.GetHeadPosition();
//		while (pos != nullptr)
//			m_oList.AddTail(objectSrc.GetNext(pos));
//		m_oLock.Unlock();
//		return *this;
//	}
//
//protected:
//	POSITION GetHeadPosition()
//	{
//		return m_oList.GetHeadPosition();
//	}
//	Type& GetNext(POSITION &pos)
//	{
//		return  m_oList.GetNext(pos);
//	}
//
//private:
//	CList<Type, Type&> m_oList;
//	CCriticalSection m_oLock;
//};

template<typename Key, class Value>
class synchronizedmap
{
	typedef typename std::map<Key, Value>::iterator mappositon;
public:

	bool RemoveKey(Key key, bool bIsLock = true)
	{
		bool bResult;
		if (true == bIsLock)
		{
			m_oLock.lock();
			bResult = m_oObject.erase(key);
		}
		else
		{
			bResult = m_oObject.erase(key);
		}

		return bResult;
	}

	void RemoveAll(bool bIsLock = true)
	{
		if (true == bIsLock)
		{
			m_oLock.lock();
			m_oObject.RemoveAll();
		}
		else
		{
			m_oObject.RemoveAll();
		}
	}

	void SetAt(Key key, Value value, bool bIsLock = true)
	{
		if (true == bIsLock)
		{
			m_oLock.lock();
			m_oObject.emplace(key, value);
		}
		else
		{
			m_oObject.emplace(key, value);
		}
	}

	void ManualUnlock()
	{
		m_oLock.unlock();
	}

	void ManualLock()
	{
		m_oLock.lock();
	}

	int GetSize()
	{
		return m_oObject.size();
	}

	bool Lookup(Key key, Value& value, bool bIsManualUnlock = false)
	{
		m_oLock.lock();
		auto bResult = false;
		auto retvalue = m_oObject[key];
		if (false == bIsManualUnlock)
			m_oLock.unlock();
		if (retvalue != nullptr)
		{
			value = std::move(retvalue);
			bResult = TRUE;
		}

		return bResult;
	}

	Value & operator[](Key key)
	{
		std::unique_lock<std::recursive_mutex> lck(m_oLock);
		return  m_oObject[key];
	}

	mappositon GetStartPos()
	{
		return m_oObject.cbegin();
	}

	synchronizedmap<Key, Value> & operator=(const synchronizedmap<Key, Value>& objectSrc)
	{
		m_oLock.lock();
		m_oObject.clear();
		auto pos = objectSrc.GetStartPos();
		auto count = objectSrc.GetSize();
		auto index = 0;
		while (pos != nullptr&& index < count)
		{
			m_oObject.emplace(pos->first, pos->second);
			++pos;
			++index;
		}
		m_oLock.unlock();
		return *this;
	}

	synchronizedmap<Key, Value> & operator=(const synchronizedmap<Key, Value>&& objectSrc)
	{
		*this = std::move(objectSrc);
		return *this;
	}

private:
	std::map<Key, Value> m_oObject;
	std::recursive_mutex m_oLock;
};